/*
 * Copyright (C) Francisco Morero Peyrona. All rights reserved.
 *
 * This software is published under the terms of Open Source
 * License version 1.1, a copy of which has been included with this
 * distribution in the License.txt file.
 */

package jdbcmanager.app;

import java.util.*;
import java.io.*;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

/**
 * Shows a exception (an instance of Throwable or any of its descendants) into a dialog box.
 *
 * @author Francisco Morero Peyrona
 *
 * @version 1.0
 */
final class JShowException extends JDialog
{
   private JPanel      pnlButtons    = new JPanel();
   private JPanel      pnlBasic      = new JPanel();
   private JButton     btnContinue   = new JButton();
   private JButton     btnExit       = new JButton();
   private JButton     btnSendMail   = new JButton();
   private JButton     btnDetails    = new JButton();
   private JTextArea   txtExcMsg     = new JTextArea();
   private JScrollPane spExcMsg      = new JScrollPane();
   private JScrollPane spStackTrace  = new JScrollPane();
   private JList       lstStackTrace = new JList( new DefaultListModel() );
   
   private boolean     bErrorOnInit  = false;
   
   /**
    * Argument zero class constructor.<br>
    * Dialog will appear centered on screen.
    */
   JShowException()
   {
      this( null, "" );
   }

   /**
    * Class constructor.<br>
    * Dialog will appear centered on screen.
    * 
    * @param owner Parent frame (dialog will appear centered about it).
    * @param sTitle Dialog title (by default "Error").
    */
   JShowException( Frame owner, String sTitle )
   {
      super( owner, sTitle, true );
      
      try
      {
         init();
         pack();
      }
      catch( Exception exc )
      {
         this.bErrorOnInit = true;  
      }
   }

   /**
    * Shows the exception passed as parameter.
    * 
    * @param exception Exception to be shown.
    */
   void show( Throwable exception )
   {
      if( this.bErrorOnInit )
      {
         exception.printStackTrace();  
      }
      else
      {
         String sMsg = exception.getLocalizedMessage();
   
         if( sMsg == null || sMsg.trim().length() == 0 )
            sMsg = "There is no description for this error.";
   
         this.txtExcMsg.setText( sMsg );
         fillStackTrace( exception );
         
         setVisible( true );
      }
   }

  //-------------------------------------------------------------------------//

   private void fillStackTrace( Throwable exc )
   {
      StringWriter sStack = new StringWriter();
      
      exc.printStackTrace( new PrintWriter( sStack, true ) );
      
      StringTokenizer  st    = new StringTokenizer( sStack.toString(), "\n" );
      DefaultListModel model = (DefaultListModel) this.lstStackTrace.getModel();
      
      while( st.hasMoreElements() )
         model.addElement( ((String) st.nextElement()).replaceAll( "\t", "      " ) );
      
      if( ! model.isEmpty() )
         this.lstStackTrace.setSelectedIndex( 0 );       
   }

   private void reportViaMail()
   {
      App.showMessage( "Report Error via email", "Option not yet implemented" );
   }
   
   private void detailsToggle()
   {
      if( spStackTrace.isVisible() )
      {
         spStackTrace.setVisible( false );
         pack();
         btnDetails.setText( btnDetails.getText().replace( '<', '>' ) );
      }
      else
      {
         spStackTrace.setVisible( true );
         setSize( getWidth(), getHeight() + 280 );
         invalidate();
         validate();
         
         btnDetails.setText( btnDetails.getText().replace( '>', '<' ) );
         lstStackTrace.grabFocus();
      }
   }

   //-------------------------------------------------------------------------//
   
   private void init() throws Exception
   {
      setDefaultCloseOperation( WindowConstants.DISPOSE_ON_CLOSE );

      // Buttons ----------------------------------------
      btnContinue.setText( "Continue" );
      btnContinue.setMnemonic( 'C' );
      getRootPane().setDefaultButton( btnContinue );
      btnContinue.addActionListener( new ActionListener()
      {
         public void actionPerformed( ActionEvent evt )
         {
            JShowException.this.dispose();
         }
      } );

      btnExit.setText( "Exit" );
      btnExit.setMnemonic( 'x' );
      btnExit.addActionListener( new ActionListener()
      {
         public void actionPerformed( ActionEvent evt )
         {
            App.stop();
         }
      });

      btnSendMail.setText( "Report" );
      btnSendMail.setIcon( new ImageIcon( getClass().getResource( "images/send_mail.gif" ) ) );
      btnSendMail.setMnemonic( 'R' );
      btnSendMail.addActionListener( new ActionListener()
      {
         public void actionPerformed( ActionEvent evt )
         {
            JShowException.this.reportViaMail();
         }
      });
      
      btnDetails.setText( "Details >>" );
      btnDetails.setMnemonic( 'D' );
      btnDetails.addActionListener(new ActionListener()
      {
         public void actionPerformed( ActionEvent evt )
         {
            JShowException.this.detailsToggle();
         }
      });

      pnlButtons.setLayout( new FlowLayout( FlowLayout.CENTER, 15, 8 ) );
      pnlButtons.add( btnContinue );
      pnlButtons.add( btnExit     );
      pnlButtons.add( btnSendMail );
      pnlButtons.add( btnDetails  );

      // Exception message -------------------------------------------
      txtExcMsg.setLineWrap( true );
      txtExcMsg.setWrapStyleWord( true );
      txtExcMsg.setEditable( false );
      txtExcMsg.setBorder( BorderFactory.createEmptyBorder( 5,5,5,5 ) );
      spExcMsg.getViewport().add( txtExcMsg );

      // Exception Stack Trace Scroll Pane
      spStackTrace.getViewport().add( lstStackTrace );
      spStackTrace.setVisible( false );

      // Mount panels -------------------------------------------
      pnlBasic.setLayout( new BorderLayout() );
      pnlBasic.add( spExcMsg  , BorderLayout.CENTER );
      pnlBasic.add( pnlButtons, BorderLayout.SOUTH  );
             
      getContentPane().setLayout( new BorderLayout( 10, 10 ) );
      getContentPane().add( pnlBasic    , BorderLayout.NORTH  );
      getContentPane().add( spStackTrace, BorderLayout.CENTER );
   }
}